namespace Asmex.FileViewer
{
    using Asmex.ObjViewer;
    using System;
    using System.Collections;
    using System.IO;
    using System.Reflection;
    using System.Text;

    public class Table : IEnumerable
    {
        private ColDesc[] _colDescs;
        private MDTables _helper;
        private Row[] _rows;
        private int _rowSize;
        private Types _type;
        private byte[] data;

        public Table(Types type, Types[] colTypes, string[] colNames, MDTables helper, BinaryReader reader)
        {
            this._type = type;
            this._helper = helper;
            this._colDescs = new ColDesc[colTypes.Length];
            for (int i = 0; i < this._colDescs.Length; i++)
            {
                this._colDescs[i] = new ColDesc(colTypes[i], colNames[i]);
            }
            this._rows = new Row[helper.GetTableRows(type)];
            this._rowSize = 0;
            foreach (ColDesc desc in this._colDescs)
            {
                this._rowSize += this._helper.SizeOfType(desc.Type);
            }
            this.data = reader.ReadBytes(this._rowSize * this.Count);
        }

        public IEnumerator GetEnumerator()
        {
            return new Enumerator(this);
        }

        private Row GetRow(int idx)
        {
            MemoryStream input = new MemoryStream(this.data);
            BinaryReader reader = new BinaryReader(input) {
                BaseStream = { Position = (long) (this._rowSize * idx) }
            };
            TableCell[] cells = new TableCell[this._colDescs.Length];
            for (int i = 0; i < this._colDescs.Length; i++)
            {
                ColDesc desc1 = this._colDescs[i];
                cells[i] = new TableCell(this._colDescs[i].Type, reader, this._helper);
            }
            input.Close();
            return new Row(cells, this);
        }

        public override string ToString()
        {
            StringBuilder builder = new StringBuilder(100);
            builder.Append(this._type.ToString());
            builder.Append(" (");
            builder.Append(this._rows.Length);
            builder.Append(")    (");
            for (int i = 0; i < this._colDescs.Length; i++)
            {
                builder.Append(this._colDescs[i].Name);
                if (i < (this._colDescs.Length - 1))
                {
                    builder.Append("  --   ");
                }
            }
            builder.Append(")");
            return builder.ToString();
        }

        [ObjViewer(false)]
        public ColDesc[] ColDescs
        {
            get
            {
                return this._colDescs;
            }
        }

        public int Count
        {
            get
            {
                return this._rows.Length;
            }
        }

        public Row this[int index]
        {
            get
            {
                if (this._rows[index] == null)
                {
                    this._rows[index] = this.GetRow(index);
                }
                return this._rows[index];
            }
        }

        [ObjViewer(false)]
        public byte[] RawData
        {
            get
            {
                return this.data;
            }
        }

        [ObjViewer(false)]
        public int RowSize
        {
            get
            {
                return this._rowSize;
            }
        }

        public Types Type
        {
            get
            {
                return this._type;
            }
        }

        private class Enumerator : IEnumerator
        {
            private int _curr;
            private Table _table;

            public Enumerator(Table table)
            {
                this._table = table;
                this.Reset();
            }

            public bool MoveNext()
            {
                this._curr++;
                return (this._curr < this._table.Count);
            }

            public void Reset()
            {
                this._curr = -1;
            }

            public object Current
            {
                get
                {
                    return this._table[this._curr];
                }
            }
        }
    }
}
